package powerga.transmission.minloss;

import static org.junit.Assert.*;

import java.util.Date;

import org.gridgain.grid.GridFactory;
import org.interpss.IpssPlugin;
import org.interpss.PluginObjectFactory;
import org.interpss.custom.IpssFileAdapter;
import org.jenetics.CompositeAlterer;
import org.jenetics.FitnessFunction;
import org.jenetics.Genotype;
import org.jenetics.Integer64Chromosome;
import org.jenetics.Integer64Gene;
import org.jenetics.MeanAlterer;
import org.jenetics.Mutator;
import org.jenetics.RouletteWheelSelector;
import org.jenetics.Statistics.Calculator;
import org.jenetics.util.Factory;
import org.junit.Test;

import powerga.general.GAUtils;

import com.interpss.common.datatype.UnitType;
import com.interpss.common.exp.InterpssException;
import com.interpss.core.CoreObjectFactory;
import com.interpss.core.aclf.AclfBranch;
import com.interpss.core.aclf.AclfBus;
import com.interpss.core.aclf.AclfNetwork;
import com.interpss.core.algo.LoadflowAlgorithm;
import com.interpss.core.net.Branch;
import com.interpss.core.net.Bus;

public class SimplePLossMinimizerTest {

	@Test
	public void testSimplePLossMinimizer() throws InterpssException, Exception {
		GridFactory.start();
		try {
			// 1. Deal with the original network
			// 1.1. Initializing
			IpssPlugin.init();		
			AclfNetwork net = PluginObjectFactory.getFileAdapter(IpssFileAdapter.FileFormat.IEEECDF).load("testData/ieee14.ieee").getAclfNet();
			// 1.2. Find the non-optimized result
		  	LoadflowAlgorithm algo = CoreObjectFactory.createLoadflowAlgorithm(net);
		  	boolean pfSuccess = algo.loadflow();
		  	Double loss = 0.0;
		  	if (pfSuccess) {	// Load flow solved successfully
			  	for (Branch thisBranch : net.getBranchList()) {
			  		double thisCurrent = net.getAclfBranch(thisBranch.getId()).current(UnitType.Amp);
			  		double thisVB = net.getAclfBus(net.getAclfBranch(thisBranch.getId()).getFromBusId()).getBaseVoltage() / 
			  				1000.0;
			  		double thisSB = net.getBaseKva() / 1000.0;
			  		double thisR = net.getAclfBranch(thisBranch.getId()).getZ().getReal() * thisVB * thisVB / thisSB;
			  		loss += thisCurrent * thisCurrent * thisR;
			  	}
			  	loss /= 1000.0;
		  	}
		  	else
		  		loss = 1.0E+10;
			
			// 2. Initialize the genetic algorithm
			int loadNumber = 0, transNumber = 0;
			for (Bus thisBus : net.getBusList()) {
				AclfBus thisAclfBus = net.getAclfBus(thisBus.getId());
				if (thisAclfBus.isLoad())
					loadNumber++;
			}
			for (Branch thisBranch : net.getBranchList()) {
				AclfBranch thisAclfBranch = net.getAclfBranch(thisBranch.getId());
				if (thisAclfBranch.isXfr())
					transNumber++;
			}
			int chromLength = loadNumber + transNumber;
//			final Factory<Genotype<Integer64Gene>> gtf = Genotype.valueOf(new PermutationChromosome(chromLength));
			final Factory<Genotype<Integer64Gene>> gtf = Genotype.valueOf(new Integer64Chromosome(0, chromLength * 10 - 1, chromLength));
			final FitnessFunction<Integer64Gene, Double> ff = new SimplePLossFunction(net, loadNumber, transNumber, 20, 9);
			SimplePLossMinimizer pmin = new SimplePLossMinimizer(gtf, ff);
			pmin.setStatisticsCalculator(new Calculator<Integer64Gene, Double>());
			pmin.setPopulationSize(300);
//			pmin.setPopulationSize(100);
			pmin.setAlterer(new CompositeAlterer<Integer64Gene>(new Mutator<Integer64Gene>(0.3), 
					new MeanAlterer<Integer64Gene>(0.6)));
			pmin.setSelectors(new RouletteWheelSelector<Integer64Gene, Double>());
			// 3. Implement the genetic algorithm
			long startTime = new Date().getTime();
			final int generations = 500;
//			final int generations = 200;
			GAUtils.printConfig("GA for PLoss optimization", pmin, generations, 
					((CompositeAlterer<?>)pmin.getAlterer()).getAlterers().toArray());		
			GAUtils.execute(pmin, generations, 10);
			System.out.println("Totally active power amount before optimization is " + loss + "kW.");
			long endTime = new Date().getTime();
			System.out.println("Totally cost " + (endTime - startTime) + " milliseconds.");
	  		assertTrue(pmin != null);
		}
		finally {
			GridFactory.stop(true);
		}
	}

}